/*
 * This file (Log.java) is protected by the GNU GPL licence (v2). 
 * Please read the license.txt attached for further informations. 
 * 
 */
package org.algoristes.alkwarel.utils;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.XMLFormatter;

/**
 * Utility to create logs for debugging purpose
 * 
 * @author Xavier Gouchet
 * 
 */
public class Log implements Constants {

	private static Logger LOGGER;
	private static Handler HANDLER;

	private static String LOG_FILE_PATH = DIR_TEMP + "alkwarel_debug.log";
	private static int LOG_FILE_SIZE = 10000;
	private static int LOG_FILE_COUNT = 1;
	

	private static List<LogListener> LISTENERS;

	/**
	 * Add a message with the SEVERE level (highest) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void severe(String msg) {
		getLogger().severe(msg);
		fireMessageLoggedEvent("! " + msg);
	}

	/**
	 * Add a message with the SEVERE level (highest) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void warning(String msg) {
		getLogger().warning(msg);
		fireMessageLoggedEvent("* " + msg);
	}

	/**
	 * Add a message with the INFO level (high) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void info(String msg) {
		getLogger().info(msg);
		fireMessageLoggedEvent(msg);
	}

	/**
	 * Add a message with the CONFIG level (midle) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void config(String msg) {
		getLogger().config(msg);
		fireMessageLoggedEvent("& " + msg);
	}

	/**
	 * Add a message with the DEBUG level (low) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void debug(String msg) {
		getLogger().fine(msg);
		fireMessageLoggedEvent("# " + msg);
	}

	/**
	 * Add a message with the VERBOSE level (lowest) to the logging system
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void verbose(String msg) {
		getLogger().finest(msg);
		fireMessageLoggedEvent("# " + msg);
	}

	/**
	 * Force a close of the File handler. This should be called before exiting
	 * the application or when the file should be restarted.
	 */
	public static void closeFileHandler() {
		if (getHandler() != null)
			try {
				HANDLER.close();
			} catch (SecurityException e) {
				System.err.println(e.getMessage());
			}
		HANDLER = null;
	}

	private static Logger getLogger() {
		if (LOGGER == null) {
			// First ever call to the Log system :
			// Create the Logger journal
			LOGGER = Logger.getLogger(LOGGING_TITLE + ".log");
			LOGGER.setLevel(Level.ALL);

			// Create the file handler linked to it
			if (getHandler() != null)
				LOGGER.addHandler(HANDLER);
		}
		return LOGGER;
	}

	private static Handler getHandler() {
		if (HANDLER == null) {
			// try to prevent IllegalArgumentException
			if (LOG_FILE_SIZE <= 0)
				LOG_FILE_SIZE = 1000;
			if (LOG_FILE_COUNT < 1)
				LOG_FILE_COUNT = 1;

			// create the FH (and try to catch any error)
			try {
				HANDLER = new FileHandler(LOG_FILE_PATH, LOG_FILE_SIZE,
						LOG_FILE_COUNT, false);
				HANDLER.setFormatter(new XMLFormatter());
			} catch (Exception e) {
				System.err.println(e.getMessage());
			}
		}
		return HANDLER;
	}
	
	private static void fireMessageLoggedEvent(String msg) {
		Iterator<LogListener> it = getListeners().iterator();
		while (it.hasNext()) {
			LogListener l = it.next();
			l.messageLoggedEvent(msg);
		}
	}

	private static List<LogListener> getListeners() {
		if (LISTENERS == null)
			LISTENERS = new LinkedList<LogListener>();
		return LISTENERS;
	}

	/**
	 * Adds a listener to the Log system
	 * @param l
	 */
	public static void addLogListener(LogListener l) {
		getListeners().add(l);
	}
}
